package com.banggood.upms.service.impl;

import com.banggood.silk.web.api.exception.SkbException;
import com.banggood.upms.bean.exception.ExceptionEnum;
import com.banggood.upms.bean.po.Tree;
import com.banggood.upms.bean.vo.search.TreeSearchCriteria;
import com.banggood.upms.common.constant.UpmsConstant;
import com.banggood.upms.dao.TreeDao;
import com.banggood.upms.service.TreeInfoService;
import com.banggood.upms.service.TreeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * @author XuChuangFeng
 */
@Service
@Transactional(rollbackFor = SkbException.class)
public class TreeServiceImpl extends BaseServiceImpl<Tree, TreeDao> implements TreeService {

    @Override
    @Autowired
    public void setDao(TreeDao dao) {
        super.dao = dao;
    }

    @Autowired
    private TreeInfoService treeInfoService;

    /**
     * 如果新插入节点的父节点存在，则会将父节点放入子节点中
     * @param tree
     * @return
     * @throws Exception
     */
    @Override
    public boolean ifParentNodeExists(Tree tree) throws Exception {
        if(StringUtils.isEmpty(tree.getParentId())) {
            return false;
        }
        // 判断要插入节点的父节点ID以及树类型是否不为空
        if(tree.getTreeType() == null) {
            throw new SkbException(ExceptionEnum.MISSING_TREE_TYPE.getCode(), ExceptionEnum.MISSING_TREE_TYPE.getMessage());
        }
        // 并且数据库中的父节点的类别跟要插入节点的类别一致
        Tree parentNode = this.selectByPrimaryKey(tree.getParentId());
        if(parentNode != null && parentNode.getTreeType().equalsIgnoreCase(tree.getTreeType())) {
            // 传入父节点
            tree.setParentTree(parentNode);
            return true;
        }
        return false;
    }

    @Override
    public boolean isEmptyTree(Tree tree) {
        TreeSearchCriteria criteria = new TreeSearchCriteria();
        criteria.setTreeType(tree.getTreeType());
        List<Tree> treeList = this.selectByCriteria(criteria);
        if(CollectionUtils.isEmpty(treeList)) {
            return true;
        }
        return false;
    }

    @Override
    public int insert(Tree tree) throws Exception {
        // 校验treeType
        if(!treeInfoService.ifTreeTypeExists(tree.getTreeType())) {
            throw new SkbException(ExceptionEnum.TREE_TYPE_NOT_EXISTS.getCode(), ExceptionEnum.TREE_TYPE_NOT_EXISTS.getMessage());
        }
        boolean isEmptyTree = this.isEmptyTree(tree);
        if(isEmptyTree) {
            // 空树，要插入的节点为根节点
            if(!StringUtils.isEmpty(tree.getParentId())) {
                throw new SkbException(ExceptionEnum.ROOT_NODE_HAS_PARENT_NODE.getCode(), ExceptionEnum.ROOT_NODE_HAS_PARENT_NODE.getMessage());
            }
        } else {
            boolean nodeCodeExists = this.ifNodeCodeExists(tree);
            if(nodeCodeExists) {
                throw new SkbException(ExceptionEnum.NODE_CODE_ALREADY_EXISTS.getCode(), ExceptionEnum.NODE_CODE_ALREADY_EXISTS.getMessage());
            }
            // 非空树，那么要插入的节点必定是个子节点，需要判断父节点是否存在
            boolean parentNodeExists = this.ifParentNodeExists(tree);
            if(!parentNodeExists) {
                throw new SkbException(ExceptionEnum.PARENT_NODE_NOT_EXIST.getCode(), ExceptionEnum.PARENT_NODE_NOT_EXIST.getMessage());
            }
        }
        tree.setTreeId(commonComponent.generateId());
        this.fillTreePath(tree);
        return dao.insert(tree);
    }

    private boolean ifNodeCodeExists(Tree tree) {
        int i = dao.ifNodeCodeExists(tree);
        if(i > 0) {
            return true;
        }
        return false;
    }

    private void fillTreePath(Tree tree) throws SkbException {
        if(StringUtils.isEmpty(tree.getParentId())) {
            // 父节点不存在，根节点直接用nodeCode作为path的起始
            tree.setPath(UpmsConstant.SLASH + tree.getNodeCode());
        } else {
            if(tree.getParentTree() == null) {
                // 将父节点的信息放入子节点中
                Tree parentNode = this.selectByPrimaryKey(tree.getParentId());
                if(parentNode.getTreeType().equalsIgnoreCase(tree.getTreeType())) {
                    throw new SkbException(ExceptionEnum.TREE_TYPE_INCONSISTENT.getCode(), ExceptionEnum.TREE_TYPE_INCONSISTENT.getMessage());
                }
                tree.setParentTree(parentNode);
            }
            tree.setPath(tree.getParentTree().getPath() + UpmsConstant.SLASH + tree.getNodeCode());
        }
    }

}
